{
  "cells": [
    {
      "metadata": {
        "id": "DhWmZgAVwDGu",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Copyright 2021 Google LLC\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "you may not use this file except in compliance with the License.\n",
        "You may obtain a copy of the License at\n",
        "\n",
        "    https://www.apache.org/licenses/LICENSE-2.0\n",
        "\n",
        "Unless required by applicable law or agreed to in writing, software\n",
        "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "See the License for the specific language governing permissions and\n",
        "limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-hbchNubOTea"
      },
      "source": [
        "# Overview\n",
        "\n",
        "This notebook summarizes the numbers of aptamers that appear to be enriched in positive pools for particular particule display experiments.  These values are turned into venn diagrams and pie charts in Figure 2. \n",
        "\n",
        "The inputs are csvs, where each row is an aptamer and columns indicate the sequencing counts within each particle display subexperiment.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "both",
        "id": "e3ZmaXPJntva"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import seaborn as sns\n",
        "import numpy as np\n",
        "import pandas as pd    "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iwjz9suGO6mA"
      },
      "source": [
        "# Parameters used in Manuscript\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0m_fyH1FO9Ce"
      },
      "outputs": [],
      "source": [
        "# Required coverage level for analysis.  This is in units of number of apatamer \n",
        "# particles (beads). This is used to minimize potential contamination. \n",
        "# For example, a tolerated bead fraction of 0.2 means that if, based on read \n",
        "# depth and number of beads, there are 100 reads expected per bead, then \n",
        "# sequences with fewer than 20 reads would be excluded from analysis.\n",
        "TOLERATED_BEAD_FRAC = 0.2 \n",
        "\n",
        "# Ratio cutoff between positive and negative pools to count as being real.\n",
        "# The ratio is calculated normalized by read depth, so if the ratio is 0.5, \n",
        "# then positive sequences are expected to have equal read depth (or more) in \n",
        "# the positive pool as the negative pool. So, as a toy example, if the \n",
        "# positive pool had 100 reads total and the negative pool had 200 reads total,\n",
        "# then a sequence with 5 reads in the positive pool and 10 reads in the \n",
        "# negative pool would have a ratio of 0.5.\n",
        "POS_NEG_RATIO_CUTOFF = 0.5\n",
        "\n",
        "# Minimum required reads (when 0 it uses only the above filters)\n",
        "MIN_READ_THRESH = 0"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SW2pi3B0hvTW"
      },
      "source": [
        "# Load in data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jTsPQUpjAVjP"
      },
      "source": [
        "##  Load in experimental conditions for Particle Display experiments\n",
        "\n",
        "The mlpd_params_df contains the experimental information for MLPD.\n",
        "\n",
        "Parameters are:\n",
        "* apt_collected: The number of aptamer bead particles collected during the FACs experiment of particle display.\n",
        "* apt_screened: The number of aptamer bead particles screened in order to get the apt_collected beads. \n",
        "* seq_input: The estimated number of unique sequences in the input sequence library during bead construction."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "height": 138
        },
        "executionInfo": {
          "elapsed": 356,
          "status": "ok",
          "timestamp": 1603828302117,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "jbCpKfz04mxN",
        "outputId": "43123110-e7e6-48db-cf92-0fa4c79f1913"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\u003cdiv\u003e\n",
              "\u003cstyle scoped\u003e\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "\u003c/style\u003e\n",
              "\u003ctable border=\"1\" class=\"dataframe\"\u003e\n",
              "  \u003cthead\u003e\n",
              "    \u003ctr style=\"text-align: right;\"\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003eapt_screened\u003c/th\u003e\n",
              "      \u003cth\u003eapt_collected\u003c/th\u003e\n",
              "      \u003cth\u003eseq_input\u003c/th\u003e\n",
              "      \u003cth\u003econdition\u003c/th\u003e\n",
              "      \u003cth\u003econdition_flag\u003c/th\u003e\n",
              "      \u003cth\u003estringency\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/thead\u003e\n",
              "  \u003ctbody\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e0\u003c/th\u003e\n",
              "      \u003ctd\u003e2400000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e35000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e100000\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_high_no_serum_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_high_no_serum_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eHigh\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e1\u003c/th\u003e\n",
              "      \u003ctd\u003e2400000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e85000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e100000\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_medium_no_serum_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_medium_no_serum_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eMedium\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e2\u003c/th\u003e\n",
              "      \u003ctd\u003e1240000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e80000.0\u003c/td\u003e\n",
              "      \u003ctd\u003e100000\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_low_no_serum_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround2_low_no_serum_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eLow\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/tbody\u003e\n",
              "\u003c/table\u003e\n",
              "\u003c/div\u003e"
            ],
            "text/plain": [
              "   apt_screened  apt_collected  ...               condition_flag stringency\n",
              "0     2400000.0        35000.0  ...    round2_high_no_serum_flag       High\n",
              "1     2400000.0        85000.0  ...  round2_medium_no_serum_flag     Medium\n",
              "2     1240000.0        80000.0  ...     round2_low_no_serum_flag        Low\n",
              "\n",
              "[3 rows x 6 columns]"
            ]
          },
          "execution_count": 3,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#@title Original PD Data Parameters\n",
        "\n",
        "# Since these are small I'm going to embed in the colab.\n",
        "apt_screened_list = [ 2.4*10**6, 2.4*10**6, 1.24*10**6]\n",
        "apt_collected_list = [3.5 * 10**4, 8.5 * 10**4,  8 * 10**4]\n",
        "seq_input = [10**5] * 3\n",
        "conditions = ['round2_high_no_serum_positive', \n",
        "              'round2_medium_no_serum_positive',\n",
        "              'round2_low_no_serum_positive']\n",
        "flags = ['round2_high_no_serum_flag', 'round2_medium_no_serum_flag', \n",
        "         'round2_low_no_serum_flag']\n",
        "stringency = ['High', 'Medium', 'Low']\n",
        "\n",
        "pd_param_df = pd.DataFrame.from_dict({'apt_screened': apt_screened_list,\n",
        "                                    'apt_collected': apt_collected_list,\n",
        "                                    'seq_input': seq_input,\n",
        "                                    'condition': conditions,\n",
        "                                    'condition_flag': flags,\n",
        "                                    'stringency': stringency})\n",
        "\n",
        "pd_param_df"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "height": 168
        },
        "executionInfo": {
          "elapsed": 311,
          "status": "ok",
          "timestamp": 1603828302739,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "HnXcw8Pg56Rw",
        "outputId": "66916855-c76f-438d-a1aa-f14c1d2623f7"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\u003cdiv\u003e\n",
              "\u003cstyle scoped\u003e\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "\u003c/style\u003e\n",
              "\u003ctable border=\"1\" class=\"dataframe\"\u003e\n",
              "  \u003cthead\u003e\n",
              "    \u003ctr style=\"text-align: right;\"\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003eapt_screened\u003c/th\u003e\n",
              "      \u003cth\u003eapt_collected\u003c/th\u003e\n",
              "      \u003cth\u003eseq_input\u003c/th\u003e\n",
              "      \u003cth\u003econdition\u003c/th\u003e\n",
              "      \u003cth\u003econdition_flag\u003c/th\u003e\n",
              "      \u003cth\u003estringency\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/thead\u003e\n",
              "  \u003ctbody\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e0\u003c/th\u003e\n",
              "      \u003ctd\u003e3283890.016\u003c/td\u003e\n",
              "      \u003ctd\u003e12204\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_very_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_very_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eVery High\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e1\u003c/th\u003e\n",
              "      \u003ctd\u003e6628573.952\u003c/td\u003e\n",
              "      \u003ctd\u003e50353\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_high_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_high_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eHigh\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e2\u003c/th\u003e\n",
              "      \u003ctd\u003e5801469.696\u003c/td\u003e\n",
              "      \u003ctd\u003e153845\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_medium_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_medium_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eMedium\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e3\u003c/th\u003e\n",
              "      \u003ctd\u003e3508412.512\u003c/td\u003e\n",
              "      \u003ctd\u003e201255\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_low_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_low_flag\u003c/td\u003e\n",
              "      \u003ctd\u003eLow\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/tbody\u003e\n",
              "\u003c/table\u003e\n",
              "\u003c/div\u003e"
            ],
            "text/plain": [
              "   apt_screened  apt_collected  ...      condition_flag stringency\n",
              "0   3283890.016          12204  ...    round1_very_flag  Very High\n",
              "1   6628573.952          50353  ...    round1_high_flag       High\n",
              "2   5801469.696         153845  ...  round1_medium_flag     Medium\n",
              "3   3508412.512         201255  ...     round1_low_flag        Low\n",
              "\n",
              "[4 rows x 6 columns]"
            ]
          },
          "execution_count": 4,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#@title MLPD Data Parameters\n",
        "apt_screened_list = [ 3283890.016, 6628573.952, 5801469.696, 3508412.512]\n",
        "apt_collected_list = [12204, 50353, 153845, 201255]\n",
        "seq_input = [200000] * 4\n",
        "conditions = ['round1_very_positive', \n",
        "              'round1_high_positive',\n",
        "              'round1_medium_positive',\n",
        "              'round1_low_positive']\n",
        "flags = ['round1_very_flag', 'round1_high_flag', 'round1_medium_flag', \n",
        "         'round1_low_flag']\n",
        "stringency = ['Very High', 'High', 'Medium', 'Low']\n",
        "mlpd_param_df = pd.DataFrame.from_dict({'apt_screened': apt_screened_list,\n",
        "                                    'apt_collected': apt_collected_list,\n",
        "                                    'seq_input': seq_input,\n",
        "                                    'condition': conditions,\n",
        "                                    'condition_flag': flags,\n",
        "                                    'stringency': stringency})\n",
        "\n",
        "\n",
        "mlpd_param_df"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vRpbBLF4tCLW"
      },
      "source": [
        "## Load CSVs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "height": 141
        },
        "executionInfo": {
          "elapsed": 560997,
          "status": "ok",
          "timestamp": 1603828878626,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "jwACDCh9PMPl",
        "outputId": "6b18aa03-545b-4ef4-eff3-4a9d2b34ec1c"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\n",
              "     \u003cinput type=\"file\" id=\"files-20b90a5d-83e9-4246-b161-06a94095f9bc\" name=\"files[]\" multiple disabled\n",
              "        style=\"border:none\" /\u003e\n",
              "     \u003coutput id=\"result-20b90a5d-83e9-4246-b161-06a94095f9bc\"\u003e\n",
              "      Upload widget is only available when the cell has been executed in the\n",
              "      current browser session. Please rerun this cell to enable.\n",
              "      \u003c/output\u003e\n"
            ],
            "text/plain": [
              "\u003cIPython.core.display.HTML at 0x7f4f50536860\u003e"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Saving mlpd_input_data_manuscript.csv to mlpd_input_data_manuscript.csv\n",
            "Saving pd_clustered_input_data_manuscript.csv to pd_clustered_input_data_manuscript.csv\n",
            "User uploaded file \"mlpd_input_data_manuscript.csv\" with length 24198752 bytes\n",
            "User uploaded file \"pd_clustered_input_data_manuscript.csv\" with length 64368063 bytes\n"
          ]
        }
      ],
      "source": [
        "# PD and MLPD sequencing counts across experiments\n",
        "# Upload pd_clustered_input_data_manuscript.csv and mlpd_input_data_manuscript.csv\n",
        "from google.colab import files\n",
        "\n",
        "uploaded = files.upload()\n",
        "\n",
        "for fn in uploaded.keys():\n",
        "  print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
        "      name=fn, length=len(uploaded[fn])))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iw2osP0aj5i1"
      },
      "outputs": [],
      "source": [
        "# Load PD Data\n",
        "with open('pd_clustered_input_data_manuscript.csv') as f:\n",
        "  pd_input_df = pd.read_csv(f)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Zl1AGYd8O6MT"
      },
      "outputs": [],
      "source": [
        "# Load MLPD data\n",
        "with open('mlpd_input_data_manuscript.csv') as f:\n",
        "  mlpd_input_df = pd.read_csv(f)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rT_gewBxKvxE"
      },
      "source": [
        "# Helper functions\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JbUfkYM0m075"
      },
      "outputs": [],
      "source": [
        "def generate_cutoffs_via_PD_stats(df, col, apt_screened, apt_collected, seq_input,\n",
        "                                  tolerated_bead_frac, min_read_thresh):\n",
        "  \"\"\"Use the experimental parameters to determine sequences passing thresholds.\n",
        "\n",
        "  Args:\n",
        "    df: Pandas dataframe with experiment results. Must have columns named \n",
        "      after the col function parameter, containing the read count, and a\n",
        "      column 'sequence'.\n",
        "    col: The string name of the column in the experiment dataframe with the \n",
        "      read count.\n",
        "    apt_screened: The integer number of aptamers screened, from the experiment \n",
        "      parameters.\n",
        "    apt_collected: The integer number of aptamers collected, from the experiment\n",
        "      parameters.\n",
        "    seq_input: The integer number of unique sequences in the sequence library \n",
        "      used to construct the aptamer particles.\n",
        "    tolerated_bead_frac: The float tolerated bead fraction threshold. In other\n",
        "      words, the sequencing depth required to keep a sequence, in units of\n",
        "      fractions of a bead based on the average expected read depth per bead. \n",
        "    min_read_threshold: The integer minimum number of reads that a sequence\n",
        "      must have in order not to be filtered.\n",
        "\n",
        "  Returns:\n",
        "    Pandas series of the sequences from the dataframe that pass filter.\n",
        "  \"\"\"\n",
        "\n",
        "  expected_bead_coverage =  apt_screened / seq_input\n",
        "  tolerated_bead_coverage = expected_bead_coverage * tolerated_bead_frac\n",
        "  bead_full_min_sequence_coverage = (1. / apt_collected) * tolerated_bead_coverage\n",
        "  col_sum = df[col].sum()\n",
        "  # Look at sequenced counts calculated observed fraction of pool and raw count.\n",
        "  seqs = df[((df[col]/col_sum) \u003e bead_full_min_sequence_coverage) \u0026 # Pool frac.\n",
        "            (df[col] \u003e min_read_thresh)   # Raw count\n",
        "            ].sequence\n",
        "  return seqs\n",
        "\n",
        "\n",
        "def generate_pos_neg_normalized_ratio(df, col_prefix):\n",
        "  \"\"\"Adds fraction columns to the dataframe with the calculated pos/neg ratio.\n",
        "\n",
        "  Args:\n",
        "    df: Pandas dataframe, expected to have columns [col_prefix]_positive and\n",
        "      [col_prefix]_negative contain read counts for the positive and negative\n",
        "      selection conditions, respectively.\n",
        "    col_prefix: String prefix of the columns to use to calculate the ratio. \n",
        "      For example 'round1_very_positive'.\n",
        "  \n",
        "  Returns:\n",
        "    The original dataframe with three new columns:\n",
        "    [col_prefix]_positive_frac contains the fraction of the total positive \n",
        "      pool that is this sequence.\n",
        "    [col_prefix]_negative_frac contains the fraction of the total negative\n",
        "      pool that is this sequence.\n",
        "    [col_prefix]_pos_neg_ratio: The read-depth normalized fraction of the \n",
        "      sequence that ended in the positive pool.\n",
        "  \"\"\"\n",
        "  col_pos = col_prefix + '_' + 'positive'\n",
        "  col_neg = col_prefix + '_' + 'negative'\n",
        "  df[col_pos + '_frac'] = df[col_pos] /  df[col_pos].sum()\n",
        "  df[col_neg + '_frac'] = df[col_neg] /  df[col_neg].sum()\n",
        "  df[col_prefix + '_pos_neg_ratio'] = df[col_pos + '_frac'] / (\n",
        "      df[col_pos + '_frac'] + df[col_neg + '_frac'])\n",
        "  return df\n",
        "\n",
        "\n",
        "def build_seq_sets_from_df (input_param_df, input_df, tolerated_bead_frac, \n",
        "                            pos_neg_ratio, min_read_thresh):\n",
        "  \"\"\"Sets flags for sequences based on whether they clear stringencies.\n",
        "\n",
        "  This function adds a column 'seq_set' to the input_param_df (one row per\n",
        "  stringency level of a particle display experiment) containing all the \n",
        "  sequences in the experiment that passed that stringency level in the \n",
        "  experiment.\n",
        "\n",
        "  Args:\n",
        "    input_param_df: Pandas dataframe with experimental parameters. Expected\n",
        "      to have one row per stringency level in the experiment and \n",
        "      columns 'apt_screened', 'apt_collected', 'seq_input', 'condition', and\n",
        "      'condition_flag'.\n",
        "    input_df: Pandas dataframe with the experimental results (counts per \n",
        "      sequence) for the experiment covered in the input_param_df. Expected\n",
        "      to have a [col_prefix]_pos_neg_ratio column for each row of the\n",
        "      input_param_df (i.e. each stringency level).\n",
        "    tolerated_bead_frac: Float representing the minimum sequence depth, in\n",
        "      units of expected beads, for a sequence to be used in analysis.\n",
        "    pos_neg_ratio: The threshold for the pos_neg_ratio column for a sequence\n",
        "      to be used in the analysis.\n",
        "    min_read_thresh: The integer minimum number of reads for a sequence to\n",
        "      be used in the analysis (not normalized, a straight count.)\n",
        "\n",
        "  Returns:\n",
        "    Nothing.\n",
        "\n",
        "  \"\"\"\n",
        "  for _, row in input_param_df.iterrows():\n",
        "    \n",
        "    # Get parameters to calculate bead fraction.\n",
        "    apt_screened = row['apt_screened']\n",
        "    apt_collected = row['apt_collected']\n",
        "    seq_input = row['seq_input']\n",
        "    condition = row['condition']\n",
        "    flag = row['condition_flag']\n",
        "    \n",
        "    # Get sequences above tolerated_bead_frac in positive pool.\n",
        "    tolerated_bead_frac_seqs = generate_cutoffs_via_PD_stats(\n",
        "        input_df, condition, apt_screened, apt_collected, seq_input, \n",
        "        tolerated_bead_frac, min_read_thresh)\n",
        "    \n",
        "    # Intersect with seqs \u003e normalized positive sequencing count ratio.\n",
        "    condition_pre = condition.split('_positive')[0]\n",
        "    ratio_col = '%s_pos_neg_ratio' % (condition_pre)\n",
        "    pos_frac_seqs = input_df[input_df[ratio_col] \u003e pos_neg_ratio].sequence\n",
        "    seqs = set(tolerated_bead_frac_seqs) \u0026 set(pos_frac_seqs)\n",
        "    input_df[flag] = input_df.sequence.isin(set(seqs))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VQJaU2bzJh0V"
      },
      "source": [
        "# Data Analysis"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ftmm7zPcD_fK"
      },
      "outputs": [],
      "source": [
        "#@title Add positive_frac / (positive_frac + negative_frac) col to df\n",
        "\n",
        "for col_prefix in ['round1_very', 'round1_high', 'round1_medium', 'round1_low']:\n",
        "  mlpd_input_df = generate_pos_neg_normalized_ratio(mlpd_input_df, col_prefix)\n",
        "  \n",
        "\n",
        "for col_prefix in ['round2_high_no_serum', 'round2_medium_no_serum', 'round2_low_no_serum']:\n",
        "  pd_input_df = generate_pos_neg_normalized_ratio(pd_input_df, col_prefix)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hR2FvzJoyYFl"
      },
      "outputs": [],
      "source": [
        "#@title Measure consistency of particle display data when increasing stringency thresholds within each experimental set (i.e PD and MLPD)\n",
        "\n",
        "build_seq_sets_from_df(pd_param_df, pd_input_df, TOLERATED_BEAD_FRAC, \n",
        "                       POS_NEG_RATIO_CUTOFF, MIN_READ_THRESH)\n",
        "\n",
        "build_seq_sets_from_df(mlpd_param_df, mlpd_input_df, TOLERATED_BEAD_FRAC, \n",
        "                       POS_NEG_RATIO_CUTOFF, MIN_READ_THRESH)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5HQNo-kJiJIj"
      },
      "source": [
        "# Generate Figure Data\n",
        "Here, we generate the raw data used to build Venn diagrams.  The final figures were render in Figma."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "height": 318
        },
        "executionInfo": {
          "elapsed": 605,
          "status": "ok",
          "timestamp": 1603828883222,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "NpkpSTK-gJxB",
        "outputId": "f30608df-5e01-465a-e13f-f3287c0c06a1"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\u003cdiv\u003e\n",
              "\u003cstyle scoped\u003e\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "\u003c/style\u003e\n",
              "\u003ctable border=\"1\" class=\"dataframe\"\u003e\n",
              "  \u003cthead\u003e\n",
              "    \u003ctr style=\"text-align: right;\"\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003esequence\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eround2_low_no_serum_flag\u003c/th\u003e\n",
              "      \u003cth\u003eround2_medium_no_serum_flag\u003c/th\u003e\n",
              "      \u003cth\u003eround2_high_no_serum_flag\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/thead\u003e\n",
              "  \u003ctbody\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"4\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e908587\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e44\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e27\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e3\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"4\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e687\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e6\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e702\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e385\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/tbody\u003e\n",
              "\u003c/table\u003e\n",
              "\u003c/div\u003e"
            ],
            "text/plain": [
              "                                                                                sequence\n",
              "round2_low_no_serum_flag round2_medium_no_serum_flag round2_high_no_serum_flag          \n",
              "False                    False                       False                        908587\n",
              "                                                     True                             44\n",
              "                         True                        False                            27\n",
              "                                                     True                              3\n",
              "True                     False                       False                           687\n",
              "                                                     True                              6\n",
              "                         True                        False                           702\n",
              "                                                     True                            385"
            ]
          },
          "execution_count": 13,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#@title  Figure 2B Raw Data\n",
        "pd_input_df.groupby('round2_low_no_serum_flag\tround2_medium_no_serum_flag\tround2_high_no_serum_flag'.split()).count()[['sequence']]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "height": 498
        },
        "executionInfo": {
          "elapsed": 396,
          "status": "ok",
          "timestamp": 1603828883625,
          "user": {
            "displayName": "",
            "photoUrl": "",
            "userId": ""
          },
          "user_tz": 420
        },
        "id": "pg5zbUUAdywu",
        "outputId": "411ae6ee-7eb1-4bb0-a27d-f1eae398f2ec"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\u003cdiv\u003e\n",
              "\u003cstyle scoped\u003e\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "\u003c/style\u003e\n",
              "\u003ctable border=\"1\" class=\"dataframe\"\u003e\n",
              "  \u003cthead\u003e\n",
              "    \u003ctr style=\"text-align: right;\"\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003esequence\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eround1_low_flag\u003c/th\u003e\n",
              "      \u003cth\u003eround1_medium_flag\u003c/th\u003e\n",
              "      \u003cth\u003eround1_high_flag\u003c/th\u003e\n",
              "      \u003cth\u003eround1_very_flag\u003c/th\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/thead\u003e\n",
              "  \u003ctbody\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"6\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e179161\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e2\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"4\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e185\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e1\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e12\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e1\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"8\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth rowspan=\"4\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e5426\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e3\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e22\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e1\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"4\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eFalse\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e2360\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e15\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth rowspan=\"2\" valign=\"top\"\u003eTrue\u003c/th\u003e\n",
              "      \u003cth\u003eFalse\u003c/th\u003e\n",
              "      \u003ctd\u003e276\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003eTrue\u003c/th\u003e\n",
              "      \u003ctd\u003e84\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/tbody\u003e\n",
              "\u003c/table\u003e\n",
              "\u003c/div\u003e"
            ],
            "text/plain": [
              "                                                                      sequence\n",
              "round1_low_flag round1_medium_flag round1_high_flag round1_very_flag          \n",
              "False           False              False            False               179161\n",
              "                                   True             False                    2\n",
              "                True               False            False                  185\n",
              "                                                    True                     1\n",
              "                                   True             False                   12\n",
              "                                                    True                     1\n",
              "True            False              False            False                 5426\n",
              "                                                    True                     3\n",
              "                                   True             False                   22\n",
              "                                                    True                     1\n",
              "                True               False            False                 2360\n",
              "                                                    True                    15\n",
              "                                   True             False                  276\n",
              "                                                    True                    84"
            ]
          },
          "execution_count": 14,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#@title Figure 2C Raw Data\n",
        "\n",
        "# To build venn (green), sum preceding True flags to get consistent sets\n",
        "# 512 nM  = 5426+3 = 5429\n",
        "# 512 \u0026 128 nM = 2360+15 = 2375\n",
        "# 512 \u0026 128 \u0026 32nM (including 8 nM) = 276+84 = 360\n",
        "# To build venn (grey) Inconsistent flags are summed (ignoring 8nM)\n",
        "# 128 nM only = 185 + 1 = 186\n",
        "# 128 nM \u0026 32 nM = 12+1 = 13\n",
        "# 32 nM only = 2\n",
        "# 32 nM and 512 nM only = 22+1 = 23\n",
        "#  \n",
        "# To build pie, look at all round1_very_flags = True\n",
        "# Green = 84\n",
        "# Grey = 15+1+3+1+1 = 21\n",
        "mlpd_input_df.groupby('round1_low_flag\tround1_medium_flag\tround1_high_flag round1_very_flag'.split()).count()[['sequence']]"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "last_runtime": {
        "build_target": "//research/biology/alphagenome:alphagenome_colab",
        "kind": "private"
      },
      "name": "Figure 2 Machine-learning-guided aptamer discovery (submission).ipynb",
      "provenance": [
        {
          "file_id": "1awuRoRT0n6iLSMTAH03CSq37KGCWxu2u",
          "timestamp": 1603475056932
        },
        {
          "file_id": "1itCfSxMlDDu7xKKROn10EXhWbXdxo1TX",
          "timestamp": 1603474788314
        },
        {
          "file_id": "10_qNH-XhiJZMakduzsEXNKEd-DEshYmQ",
          "timestamp": 1603357039688
        },
        {
          "file_id": "1pPg_LPXmogMdDy8aAL7E1Hul-jYibALI",
          "timestamp": 1603150899877
        },
        {
          "file_id": "1LIbYnfPYSbjPtFZzwtXR6O60QvL4RdO6",
          "timestamp": 1603141230651
        },
        {
          "file_id": "16B2JDwBLtT2JOMJGeyla-SjS29bYQgvK",
          "timestamp": 1593452704228
        },
        {
          "file_id": "1iXrZrd9UCDJ9oaqBxOC7EHtQpnvhVkW4",
          "timestamp": 1593120468277
        },
        {
          "file_id": "1DqHktleGMNONMackZeve8sElQ2fOcFhL",
          "timestamp": 1586448562556
        },
        {
          "file_id": "1Dk8MgJu86W_KO8peayyo0Y02pfLkqdqX",
          "timestamp": 1583452332056
        },
        {
          "file_id": "1ru5ARNkGB19RTacCND48NJhnR3o2qqNr",
          "timestamp": 1582239842118
        },
        {
          "file_id": "1T1XL25bS7L81erHwCzf6HVueqPo42uit",
          "timestamp": 1581621943122
        },
        {
          "file_id": "1DQTQ5EmzbqpVflUaCJYZhIKLbxP19x2g",
          "timestamp": 1581360733451
        },
        {
          "file_id": "1pIJUGr60UyOf2le4ehPaR2HFDWT7fB3Q",
          "timestamp": 1581018638744
        },
        {
          "file_id": "1mpk7R6pNQUD6tdW9aaSt0D784PkVoC5f",
          "timestamp": 1580404906728
        },
        {
          "file_id": "1WFx5uXw0gzNEVUFfik9l_Q4zvD1XP7mq",
          "timestamp": 1576173640261
        },
        {
          "file_id": "1fFgkqbG8adO4L9rpozRgJ98ClcKwPcbw",
          "timestamp": 1566493555486
        }
      ],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
